package monitor;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;

import comunicacion.Conector;

import estrategia.ParametrosGlobales;

public class ManagerObjetos {
	
	private static final int FUERTE = 0;
	private static final int ROJO = 1;
	private static final int AZUL = 2;
	private static final int ELIMINADO = 3;
	
	private int miRobot;
	private int[] clasificaciones;
	
	private static ManagerObjetos instance = null;
	
	
	private ManagerObjetos(Conector entorno) throws IOException {		
		miRobot = ParametrosGlobales.MI_ROBOT;
		clasificaciones = new int[ParametrosGlobales.CANTIDAD_OBJETOS];
		for (int i=0; i<clasificaciones.length; i++) {
			clasificaciones[i] = ELIMINADO;
		}
		
		cargarClasificacionesDesdeArchivo();
		
		imprimirClasificacionesActuales();
	}
	
	/**
	 * Funcion para obtener la instancia de ManagerObjetos. Puede ser invocada con null, sii 
	 * se conoce de antemano que fue invocada previamente con un valor no nulo.
	 * */
	public static ManagerObjetos getInstance(Conector entorno) throws IOException {		
		if (instance == null) {
			instance = new ManagerObjetos(entorno);		
		}
		return instance;
	}
	
	
	/**
	 * Devuelve una coleccion con los indices de los objetos del
	 * entorno que estan activos, es decir son fuertes o ejercitos
	 * que no han sido derrotados por otro. 
	 * -> Nunca devuelve a "miRobot"
	 */
	public ArrayList<Integer> getObjetosActivos() {
		ArrayList<Integer> objetosActivos = new ArrayList<Integer>();
		
		for (int i=0; i<clasificaciones.length; i++) {
			if (i != miRobot && !estaEliminado(i)) {
				objetosActivos.add(new Integer(i));
			}
		}
		
		return objetosActivos;
	}
	
	/**
	 * Devuelve una coleccion con los indices de los enemigos que
	 * estan activos, es decir, no han abandonado el juego.
	 */
	public ArrayList<Integer> getAliadosActivos() {
		ArrayList<Integer> aliadosActivos = new ArrayList<Integer>();
		
		for (int i=0; i<clasificaciones.length; i++) {
			if (i != miRobot && esAliado(i) && !estaEliminado(i)) {
				aliadosActivos.add(new Integer(i));
			}
		}
		
		return aliadosActivos;
	}
	
	/**
	 * Devuelve una coleccion con los indices de los enemigos que
	 * estan activos, es decir, no han abandonado el juego.
	 */
	public ArrayList<Integer> getEnemigosActivos() {
		ArrayList<Integer> enemigosActivos = new ArrayList<Integer>();
		
		for (int i=0; i<clasificaciones.length; i++) {
			if (i != miRobot && esEnemigo(i) && !estaEliminado(i)) {
				enemigosActivos.add(new Integer(i));
			}
		}
		
		return enemigosActivos;
	}
	
	/**
	 * Devuelve una coleccion con los indices de los ejercitos que
	 * estan activos, es decir, no han abandonado el juego.
 	 * -> Nunca devuelve a "miRobot"
	 */
	public ArrayList<Integer> getEjercitosActivos() {
		ArrayList<Integer> ejercitosActivos = new ArrayList<Integer>();
		
		for (int i=0; i<clasificaciones.length; i++) {
			if (i != miRobot && esEjercito(i) && !estaEliminado(i)) {
				ejercitosActivos.add(new Integer(i));
			}
		}
		
		return ejercitosActivos;
	}
	
	/**
	 * Devuelve una coleccion con los identificadores de los fuertes
	 */
	public ArrayList<Integer> getFuertes() {
		ArrayList<Integer> fuertes = new ArrayList<Integer>();
		
		for (int i=0; i<clasificaciones.length; i++) {
			if (esFuerte(i)) {
				fuertes.add(new Integer(i));
			}
		}
		
		return fuertes;
	}
	
	public boolean esEjercito(int idObjeto) {
		return (clasificaciones[idObjeto] != FUERTE);
	}
	
	public boolean esAliado(int idEjercito) {
		if (esEjercito(idEjercito)) {
			return (clasificaciones[idEjercito] == clasificaciones[miRobot]);
		}
		return false;
	}
	
	public boolean esEnemigo(int idEjercito) {
		if (esEjercito(idEjercito)) {
			return (clasificaciones[idEjercito] != clasificaciones[miRobot]);
		}
		return false;
	}
	
	public boolean esFuerte(int idObjeto) {
		return (clasificaciones[idObjeto] == FUERTE);			
	}
	
	public boolean estaEliminado(int idObjeto) {
		return (clasificaciones[idObjeto] == ELIMINADO); 
	}
	
	public void deshabilitarEjercitoDerrotado(int idEjercito) {
		if (!esEjercito(idEjercito)) {
			System.out.println("El objeto " + idEjercito + "no es un ejercito");
		}
		
		clasificaciones[idEjercito] = ELIMINADO;		
	}
	
	private void cargarClasificacionesDesdeArchivo() throws IOException {
		Properties properties = new Properties();	    
    	InputStream is = new FileInputStream(ParametrosGlobales.NOMBRE_ARCHIVO_CLASIFICACION_OBJETOS);
        properties.load(is); 
				
        if (properties.containsKey("FUERTES")) {
			String lineaFuertes = properties.getProperty("FUERTES");
			if (! lineaFuertes.trim().equals("")) {
				String[] fuertes = lineaFuertes.split(",");
				for (int i=0; i<fuertes.length; i++) {
					int fuerte = Integer.parseInt(fuertes[i]);
					clasificaciones[fuerte] = FUERTE;
				}
			}				
		} else {
			avisarError("FUERTES");
		}
		
		if (properties.containsKey("ROJOS")) {
			String lineaRojos = properties.getProperty("ROJOS");
			if (! lineaRojos.trim().equals("")) {
				String[] rojos = lineaRojos.split(",");
				for (int i=0; i<rojos.length; i++) {
					int rojo = Integer.parseInt(rojos[i]);
					clasificaciones[rojo] = ROJO;
				}	
			}
		} else {
			avisarError("ROJOS");
		}
		
		if (properties.containsKey("AZULES")) {
			String lineaAzules = properties.getProperty("AZULES");
			if (! lineaAzules.trim().equals("")) {
				String[] azules = lineaAzules.split(",");
				for (int i=0; i<azules.length; i++) {
					int azul = Integer.parseInt(azules[i]);
					clasificaciones[azul] = AZUL;
				}
			}
		} else {
			avisarError("AZULES");
		}
	}
	
	public void imprimirClasificacionesActuales() {
		for (int i=0; i<clasificaciones.length; i++) {
			System.out.print("Objeto " + i + " :: ");
			String clase = "HAY_ALGUN_ERROR";
			switch (clasificaciones[i]) {
			case FUERTE:
				clase = "FUERTE"; 
				break;
			case ROJO: 
				clase = "ROJO";
				break;
			case AZUL:
				clase = "AZUL";
				break;
			case ELIMINADO:
				clase = "ELIMINADO";
				break;
			}
			System.out.println(clase);
		}
	}
	
	private void avisarError(String claveInexistente) throws IOException {
		throw new IOException("Falta propiedad " + claveInexistente + " en el archivo de propiedades " + 
				ParametrosGlobales.NOMBRE_ARCHIVO_CLASIFICACION_OBJETOS);
	}

}
